import { AfterContentInit, ChangeDetectorRef, ContentChildren, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef } from '@angular/core';
import { QueryList } from '@angular/core';
import { Component, OnInit, ChangeDetectionStrategy, forwardRef } from '@angular/core';
import { AbstractControl, ControlValueAccessor, FormArray, FormBuilder, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator, Validators } from '@angular/forms';

import { uniqueId } from 'lodash';
import { inValidFormTip } from 'src/app/util/form-invaild';
import { TdDirective } from '../directive/td.directive';
import { ThDirective } from '../directive/th.directive';
import { CustomFormConfig } from './type';

export interface ContentFormConfig {
  header: string;
  controlName?: string;
  defaultValue?: any;
  type: 'input' | 'date' | 'select' | 'number' | 'discount' | 'radio';
  validation: Array<any>;
  errorTip?: string;
  options?: Array<{ label: string, value: any; }>;
  controlMode?: 'readonly' | 'edit';
  hide?: boolean;
  placeholder?: string;
  allowClear?: boolean;
  showRequiredTip?: boolean;
  template?: TemplateRef<any> | null;
  maxLength?: string | number | any;
  max?: number | any;
  format?: (value: any) => any;
}

@Component({
  selector: 'wf-custom-table',
  templateUrl: './custom-table.component.html',
  styleUrls: ['./custom-table.component.less'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomTableComponent),
      multi: true
    },
    { provide: NG_VALIDATORS, useExisting: CustomTableComponent, multi: true }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomTableComponent implements OnInit, OnChanges, ControlValueAccessor, AfterContentInit, Validator {

  @Input() tableLayout: any = 'fixed';
  @Input() tableAlign: "left" | "right" | "center" | null = 'center';
  @Input() enableUniqueId = false;
  @Input() enableNo = false;
  @Input() limit: number = 0;
  @Input() enableLimit = false;
  @Input() minLimit: number = 0;
  @Input() enableMinLimit = false;
  @Input() formConfig: CustomFormConfig[] = [
    {
      header: '名字',
      controlName: 'name',
      defaultValue: '',
      type: 'input',
      validation: [Validators.required],
      errorTip: '必填',
    },
    {
      header: '年龄',
      controlName: 'age',
      defaultValue: '',
      type: 'input',
      validation: [Validators.required],
      errorTip: '必填',
    },
    {

      header: '内容',
      controlName: 'content',
      type: 'input',
      validation: [Validators.required]
    },
  ];
  @Output() logger = new EventEmitter<string>();
  @Output() addChange = new EventEmitter<any>();
  @Output() removeChange = new EventEmitter<any>();

  headerConfig!: Array<{ header: string; controlName: string; hide?: boolean, template: TemplateRef<any>; } | any>;
  contentConfig!: Array<ContentFormConfig>;
  thTemplateOfNullInForm: { template: TemplateRef<any>; width: any; }[] = [];
  tdTemplateOfNullInForm: { template: TemplateRef<any>; width?: any; }[] = [];

  form: FormGroup;

  formatterPercent = (value: number) => `${value} %`;
  parserPercent = (value: string) => value.replace(' %', '');

  private controlsConfig!: {
    [key: string]: any;
  };


  get arrayData() {
    return (this.form.get('formArray') as FormArray)?.controls as any[];
  }

  @ContentChildren(TdDirective) tdDirectiveList!: QueryList<TdDirective>;
  @ContentChildren(ThDirective) thDirectiveList!: QueryList<ThDirective>;

  constructor(
    private cd: ChangeDetectorRef,
    private fb: FormBuilder,
  ) {
    this.form = this.fb.group({
      formArray: this.fb.array([])
    });
  }

  // 若table为空或者有一行数据校验不通过，则整个组件校验不通过
  validate(control: AbstractControl): ValidationErrors | null {
    const arr = (this.form.get('formArray') as FormArray).controls || [];
    if (arr.some(row => row.status === 'INVALID')) {
      return { tableRequiredError: true };
    }
    return null;
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.formConfig && !changes.formConfig.firstChange) {
      this.controlsConfig = this.parseFormConfig(this.formConfig);
      this.headerConfig = this.parseHeader(this.formConfig);
      this.contentConfig = this.parseContent(this.formConfig);
    }
  }

  ngOnInit(): void {
    (this.form as FormGroup).valueChanges.subscribe(res => {
      this.propagateChange(res.formArray);
    });

    this.controlsConfig = this.parseFormConfig(this.formConfig);
    this.headerConfig = this.parseHeader(this.formConfig);
    this.contentConfig = this.parseContent(this.formConfig);
  }

  ngAfterContentInit(): void {
    this.matchTemplate(this.thDirectiveList, this.tdDirectiveList);
  };

  // 添加行
  addRow(): void {
    if (this.form.valid) {
      if (this.enableLimit && (this.form.get('formArray') as FormArray).length < this.limit) {
        const controlsConfigTemp = Object.assign({}, this.controlsConfig);
        if (this.enableUniqueId) {
          controlsConfigTemp['uniqueId'] = [uniqueId()];
        }
        (this.form.get('formArray') as FormArray).push(this.fb.group(controlsConfigTemp));
        this.addChange.emit(this.fb.group(controlsConfigTemp));
      } else if (this.enableLimit) {
        this.logger.emit(`最多添加${this.limit}条!`);
      } else {
        const controlsConfigTemp = Object.assign({}, this.controlsConfig);
        if (this.enableUniqueId) {
          controlsConfigTemp['uniqueId'] = [uniqueId()];
        }
        (this.form.get('formArray') as FormArray).push(this.fb.group(controlsConfigTemp));
        this.addChange.emit(this.fb.group(controlsConfigTemp));
      }
      this.cd.markForCheck();
    } else {
      ((this.form.get('formArray') as FormArray).controls as FormGroup[]).forEach((item: FormGroup) => {
        inValidFormTip(item);
      });
      this.cd.markForCheck();
    }
  }

  // 删除行
  deleteRow(i: number): void {
    if (this.enableMinLimit) {
      if ((this.form.get('formArray') as FormArray).length > this.minLimit) {
        this.removeChange.emit((this.form.get('formArray') as FormArray).controls[i]);
        (this.form.get('formArray') as FormArray).removeAt(i);
      } else {
        this.logger.emit(`至少${this.minLimit}条!`);
      }
    } else {
      this.removeChange.emit((this.form.get('formArray') as FormArray).controls[i]);
      (this.form.get('formArray') as FormArray).removeAt(i);
    }
  }

  writeValue(obj: any): void {
    (this.form.get('formArray') as FormArray).clear();
    if (obj && obj.length > 0) {
      if (this.contentConfig.length > 0) {
        obj.forEach((item: any, i: number) => {
          const controlsConfigTemp = Object.assign({}, this.controlsConfig);
          if (this.enableUniqueId) {
            controlsConfigTemp['uniqueId'] = [uniqueId()];
          }
          (this.form.get('formArray') as FormArray).push(this.fb.group(controlsConfigTemp));
          (this.form.get('formArray') as FormArray).controls[i].patchValue(item);
        });
      }
    }
    this.cd.markForCheck();
  }

  registerOnChange(fn: any): void {
    this.propagateChange = fn;
  };

  registerOnTouched(fn: any): void {

  };
  setDisabledState?(isDisabled: boolean): void {

  }
  private propagateChange = (_: any) => { };

  private matchTemplate(thList: QueryList<ThDirective>, tdList: QueryList<TdDirective>) {
    this.headerConfig = this.headerConfig.map(item => {
      const OrderThDirective = thList.find(th => th.controlName === item.controlName);
      return {
        ...item,
        template: OrderThDirective ? OrderThDirective.templateRef : null
      };
    });

    this.thTemplateOfNullInForm = thList.filter(item => !item.controlName).map(item => ({
      template: item.templateRef,
      width: item.width ? item.width : null
    }));

    this.contentConfig = this.formConfig.map(item => {
      const OrderTdDirective = tdList.find(td => td.controlName === item.controlName);
      return {
        ...item,
        template: OrderTdDirective ? OrderTdDirective.templateRef : null
      };
    });

    this.tdTemplateOfNullInForm = tdList.filter(item => !item.controlName).map(item => ({
      template: item.templateRef,
      // width: item.width ? item.width : null
    }));
  }

  // 解析配置生成controls
  private parseFormConfig(customFormConfig: CustomFormConfig[]) {
    const controls: { [key: string]: any; } = {};
    customFormConfig.forEach(item => {
      if (item.controlName) {
        let defaultValue = null;
        if (item.defaultValue === false) {
          defaultValue = false;
        }
        defaultValue = item.defaultValue;
        controls[item.controlName] = [defaultValue, item.validation];
      }
    });
    return controls;
  }
  // 解析配置生成header
  private parseHeader(customFormConfig: CustomFormConfig[]) {
    return customFormConfig.map(item => ({
      header: item.header,
      hide: item.hide,
      width: item.width ? item.width : null,
      controlName: item.controlName,
      template: null
    }));
  }
  // 解析配置生成Content
  private parseContent(customFormConfig: CustomFormConfig[]): Array<ContentFormConfig> {

    return customFormConfig.map(item => ({
      header: item.header,
      controlName: item.controlName,
      template: null,
      defaultValue: item.controlName,
      type: item.type,
      validation: item.validation,
      errorTip: item.errorTip,
      options: item.options,
      controlMode: item.controlMode,
      hide: item.hide,
      placeholder: item.placeholder,
      allowClear: item.allowClear,
      showRequiredTip: item.showRequiredTip,
      maxLength: item.maxLength,
      max: item.max,
    }));
  }

}
